import { IconConfig, MainScene, ScenePosition, TextGroupConfig } from '../scenes/types';

interface ToggleAlphaTween extends Phaser.Types.Tweens.TweenBuilderConfig {
  scene: Phaser.Scene;
  targets: any;
  duration?: number;
  delay?: number;
  alpha: 0 | 1;
}

export const isDev = process.env.NODE_ENV === 'development';
export const isTst = process.env.NODE_ENV === 'tst';
export const isPro = process.env.NODE_ENV === 'production';

const url = isTst ? 'https://scplugins.oss-cn-shenzhen.aliyuncs.com' : 'https://oss.shencom.cn';
export const ossPath = isDev ? 'assets' : `${url}/plugins${isTst ? '/test' : ''}/scloud/app/phaser-luohu-40/assets`;

/**
 * 当前相机底部对应的世界的Y
 *
 * @param {MainScene} scene
 * @returns number
 * @memberof MainScene
 */
export const getViewportY = (scene: MainScene) => {
  const cameras = scene.cameras.main;
  // const Y = Math.floor(cameras.scrollY + cameras.height);
  const Y = Math.floor(scene.camerasScrollY + cameras.height);
  return Y;
};

/**
 * 计算X值
 *
 * @param {number} distanceX 移动X距离
 * @param {number} leftX 元素开始X点位
 * @param {number} percent 动画执行百分比
 * @returns
 * @memberof MainScene
 */
export const getAnimationEndX = (distanceX: number, leftX: number, percent: number) => {
  const offsetX = distanceX * percent;
  const x = leftX + offsetX;
  return x;
};

/**
 * 计算Y值
 *
 * @param {MainScene} scene
 * @param {number} height 对象的高
 * @param {number} animate_offset // 开始执行位置偏移量
 * @returns
 * @memberof MainScene
 */
export const getAnimationEndY = (scene: MainScene, height: number, animate_offset: number) => {
  const viewportY = getViewportY(scene);
  return viewportY - height - animate_offset;
};
/**
 * 计算百分比
 *
 * @param {number} viewportY
 * @param {number} start 开始执行的场景位置
 * @param {number} distance 元素移动的距离
 * @returns
 * @memberof MainScene
 */
export const getPercent = (viewportY: number, start: number, distance: number) => {
  const offset = viewportY - start;
  const percent = offset / distance;
  return percent;
};

export const toggleAlphaTween = (op: ToggleAlphaTween) => op.scene.tweens.add({
  targets: op.targets,
  repeat: 0,
  delay: op.delay,
  duration: op.duration || 300,
  onComplete: op.onComplete,
  props: { alpha: op.alpha },
});

export const setBackground = (scene: Phaser.Scene, name: string) => {
  const bg = scene.add.image(0, 0, name);
  bg.setOrigin(0, 0);
  bg.setName('bg');
  return bg;
};

interface CreateBaseTextProp {
  text: string;
  style?: Phaser.Types.GameObjects.Text.TextStyle;
  x?: number;
  y?: number;
  name?: string;
}

interface CreateTextProp extends CreateBaseTextProp {
  /** 对齐方式 默认:left */
  align?: 'left' | 'center' | 'right';
}
class CerateStrokeText extends Phaser.GameObjects.Text {
  constructor(scene: Phaser.Scene, op: CreateBaseTextProp) {
    super(scene, op.x || 0, op.y || 0, op.text, op.style || {});

    this.setStroke('#fff', 6);

    if (op.name) this.setName(op.name);
  }
}
export const createDateText = (scene: Phaser.Scene, op: CreateTextProp) => {
  const text = new CerateStrokeText(scene, op);
  const { color = '#f00', fontSize = '50px', fontStyle = 'bold' } = op.style || {};
  text.setStyle({ fill: color, align: op.align || 'left', fontSize, fontStyle });

  return text;
};
export const createDocsText = (scene: Phaser.Scene, op: CreateTextProp) => {
  const text = new CerateStrokeText(scene, op);
  const { color = '#5E5018', fontSize = '30px', fontStyle = 'bold' } = op.style || {};
  text.setStyle({ fill: color, align: op.align || 'left', fontSize, fontStyle });
  text.setLineSpacing(12);

  return text;
};

export const createHomeBg = (scene: Phaser.Scene) => {
  const { height, width } = scene.cameras.main;
  const group = scene.add.container();
  const graphics = new Phaser.GameObjects.Graphics(scene);
  graphics.fillStyle(0xfdfae9, 1);
  graphics.fillRect(0, 0, width, height);

  const home_bg = new Phaser.GameObjects.Image(scene, 0, 0, 'g1_bg');
  home_bg.setDisplayOrigin(0, 0);
  home_bg.y = (height - home_bg.height) / 2;

  group.add([graphics, home_bg]);

  group.setSize(width, height);

  return group;
};

export const createTestBg = (scene: Phaser.Scene, y: number, height: number) => {
  const a = scene.add.graphics({
    fillStyle: { color: 0xd61298, alpha: 0.3 },
  });
  a.fillRect(0, y, scene.cameras.main.width, height);
};

interface CreateObject {
  scene: MainScene;
  scenePosition: ScenePosition;
  iconConfig: IconConfig;
  type: 'image' | 'container';
}

const createObject = ({ scene, scenePosition, iconConfig, type }: CreateObject) => {
  const {
    name,
    image,
    offsetX = scenePosition.x,
    animate_distance = 0,
    offsetY = 0,
    distanceX = 0,
    scale = 1,
    angle = 0,
    alpha = 1,
    distanceY = 0,
    animate_offset = 0,
  } = iconConfig;
  let icon: any;
  if (type === 'container') {
    icon = scene.add.container(scenePosition.x, scenePosition.y);
  } else {
    icon = scene.add.image(scenePosition.x + offsetX, scenePosition.y + offsetY, image!);
  }

  const cameras_H = scene.cameras.main.height;

  icon.setName(name);
  icon.setAlpha(alpha);
  icon.setAngle(angle);
  if (typeof scale === 'number') {
    icon.setScale(scale);
  } else {
    icon.setScale(...scale);
  }

  const getPosition = (x: number, y: number) => {
    const topY = y + offsetY; // 人物开始Y点
    const bottomY = topY + icon.height; // 人物结束Y点
    const leftX = x + offsetX; // 人物开始X点
    const rightX = leftX + icon.width; // 人物结束X点
    return {
      topY,
      bottomY,
      leftX,
      rightX,
    };
  };

  const getAnimatePosition = (start: number) => {
    const _start = animate_offset + start; // 开始动画移动的位置
    const _end = _start + distanceY; // 结束动画移动的位置
    return { start: _start, end: _end };
  };

  type ResetAnimateType = 'end' | 'start' | 'going' | 'not';

  interface AnimateReturnType extends ReturnType<typeof getPosition> {
    y_animate_start?: number;
    y_animate_end?: number;
  }

  interface ResetAnimateParam extends AnimateReturnType {
    /** 百分比 */
    percent: number;
    moveX: number;
    moveY: number;
  }

  interface ResetAnimateOption {
    debug?: boolean;
    distance?: number;
  }

  interface Prop<T extends ResetAnimateType, K> {
    type: T;
    data: K;
  }
  type Going = Prop<'going', ResetAnimateParam>;
  type StartEnd = Prop<'start' | 'end' | 'not', AnimateReturnType>;

  interface ResetAnimateCallback {
    (op: Going | StartEnd): void;
  }

  interface ResetAnimate {
    (callback: ResetAnimateCallback, position?: ResetAnimateOption): void;
  }

  const { topY, bottomY, leftX, rightX } = getPosition(scenePosition.x, scenePosition.y);

  const y_animate_default = bottomY + animate_offset; // y轴动画默认的位置
  const y_animate_start = y_animate_default - animate_distance; // y轴动画开始的位置
  const y_animate_end = y_animate_default + distanceY + animate_distance; // y轴动画结束的位置

  const resetAnimate: ResetAnimate = (callback: ResetAnimateCallback, position: any): any => {
    const viewportY = getViewportY(scene);
    const { debug } = position || {};

    const op = { topY, bottomY, leftX, rightX, y_animate_start, y_animate_end };
    if (debug) console.log('y_animate :>> ', viewportY, y_animate_start, y_animate_end);
    if (viewportY < y_animate_start && viewportY > y_animate_start - cameras_H / 2) {
      if (debug) console.log('y_animate_start :>> ', viewportY, y_animate_start, y_animate_end);
      if (icon.x !== leftX) icon.setX(leftX);
      if (icon.y !== topY) icon.setY(topY);
      callback({ data: op, type: 'start' });
    } else if (viewportY > y_animate_end && viewportY < y_animate_end + cameras_H / 2) {
      if (debug) console.log('y_animate_end :>> ', icon.y, topY, distanceY);
      if (icon.x !== leftX + distanceX) icon.setX(leftX + distanceX);
      if (icon.y !== topY + distanceY) icon.setY(topY + distanceY);
      callback({ data: op, type: 'end' });
    } else if (viewportY > y_animate_start && viewportY < y_animate_end) {
      if (debug) console.log('y_animate_going :>> ', icon.y, topY, distanceY);
      const percent = getPercent(viewportY, y_animate_start, distanceY + animate_distance * 2);
      const moveX = leftX + distanceX * percent;
      const moveY = topY + distanceY * percent;
      callback({
        type: 'going',
        data: { ...op, percent, moveX, moveY },
      });
    } else {
      callback({ data: op, type: 'not' });
    }
  };

  return {
    config: {
      offsetY,
      offsetX,
      distanceY,
      distanceX,
      animate_offset,
      animate_distance,
      y_animate_start,
      y_animate_end,
    },
    icon,
    getPosition,
    resetAnimate,
    getAnimatePosition,
  };
};

/**
 * 创建元素
 *
 * @param {MainScene} scene
 * @param {ScenePosition} ScenePosition 场景的开始位置
 * @param {IconConfig} iconConfig 元素配置
 * @returns
 */
export const createImageObject = (scene: MainScene, scenePosition: ScenePosition, iconConfig: IconConfig) => {
  const { origin = 0 } = iconConfig;
  const obj = createObject({ scene, scenePosition, iconConfig, type: 'image' });

  const icon = obj.icon as Phaser.GameObjects.Image;

  if (typeof origin === 'number') {
    icon.setOrigin(origin);
  } else {
    icon.setOrigin(...origin);
  }

  return {
    ...obj,
    icon,
  };
};

/**
 * 创建元素
 *
 * @param {MainScene} scene
 * @param {ScenePosition} ScenePosition 场景的开始位置
 * @param {IconConfig} iconConfig 元素配置
 * @returns
 */
export const createContainerObject = (scene: MainScene, scenePosition: ScenePosition, iconConfig: IconConfig) => {
  const obj = createObject({ scene, scenePosition, iconConfig, type: 'container' });
  const icon = obj.icon as Phaser.GameObjects.Container;
  return {
    ...obj,
    icon,
  };
};

/**
 * 创建文字组
 *
 * @param {MainScene} scene
 * @param {ScenePosition} scenePosition 场景的开始位置
 * @param {TextGroupConfig} config 文字组配置
 * @returns
 */
export const createTextGroup = (scene: MainScene, scenePosition: ScenePosition, config: TextGroupConfig) => {
  const textGroup = scene.add.container();
  const cameras_W = scene.cameras.main.width;
  const {
    name,
    text,
    direction,
    offsetX = 0,
    offsetY = 0,
    distanceX,
    distanceY = 300,
    animate_offset = 0,
    animate_start_disabled = false,
    animate_end_disabled = false,
    align,
    dateConfig = {},
    docsConfig = {},
  } = config;
  const textDate = createDateText(scene, {
    style: dateConfig,
    align,
    text: text.date,
    x: 0,
    y: 0,
    name: 'textDate',
  });

  const textDocs = createDocsText(scene, {
    style: docsConfig,
    align,
    text: text.docs,
    x: 0,
    y: textDate.y + textDate.height * 1.2,
    name: 'textDocs',
  });

  // 文字总宽高
  const width = textDocs.width > textDate.width ? textDocs.width : textDate.width;
  const height = textDate.height + textDocs.height;

  if (align === 'right') {
    textDate.setX(width - textDate.width);
    textDocs.setX(width - textDocs.width);
  }

  // 未设置 x 轴移动距离，默认从两侧进入到目标位置
  const getOffsetX = {
    left: typeof distanceX === 'undefined' ? -textDocs.width : offsetX - distanceX,
    right: typeof distanceX === 'undefined' ? cameras_W + (align === 'right' ? width : 0) : offsetX - (align === 'right' ? width : 0) + distanceX,
  };

  const getOffsetY = {
    top: offsetY - distanceY,
    bottom: offsetY + distanceY,
  };

  // x 轴偏移量
  const startOffsetX = direction === 'left' || direction === 'right' ? getOffsetX[direction] : offsetX;
  // y 轴偏移量
  const startOffsetY = direction === 'top' || direction === 'bottom' ? getOffsetY[direction] : offsetY;
  // x 轴初始值
  const x = scenePosition.x + startOffsetX;
  // y 轴初始值
  const y = scenePosition.y + startOffsetY;

  // 元素结束位置
  const endX = direction === 'left' || direction === 'right' ? (align === 'right' ? cameras_W - offsetX - width : offsetX) : x;
  const endY = direction === 'top' ? y + distanceY : direction === 'bottom' ? y - distanceY : y;

  // console.log('startX, startY: ', align, x, y, startOffsetX, startOffsetY, endX, endY, endX - x);

  textGroup
    .add([textDate, textDocs])
    .setName(name)
    .setX(x)
    .setY(y)
    .setDepth(2)
    .setAlpha(0)
    .setData({
      data: {
        direction,
        width,
        height,
        x,
        y,
        distanceX: endX - x,
        distanceY,
        endX,
        endY,
        animate_offset,
        animate_start_disabled,
        animate_end_disabled,
        name,
        getAnimationEndY: (percent: number) => y + (endY - y) * percent,
      },
    });

  textGroup.width = width;
  return textGroup;
};

/**
 * 计算缩放值
 *
 * @static
 * @param {number} percent 百分比
 * @param {number} start 开始值
 * @param {number} end 结束值
 * @returns
 * @memberof MainScene
 */
export const getProcessValue = (percent: number, start: number, end: number) => {
  const diff = end - start;
  return start + diff * percent;
};

/**
 * 文字出场动画
 *
 * @param {MainScene} scene
 * @param {Phaser.GameObjects.Container} textDom 文字组
 * @param {TextGroupConfig} config 文字组配置
 * @memberof MainScene
 */
export const textAnimation = (scene: MainScene, textDom: Phaser.GameObjects.Container) => {
  const textData = textDom.getData('data');
  const viewportY = getViewportY(scene);
  const cameras_H = scene.cameras.main.height;

  const bottomY = textData.y + textData.height; // 文字结束Y点
  const animate_start = bottomY + textData.animate_offset;
  const animate_end = animate_start + textData.distanceY; // 结束动画移动的位置
  if (viewportY > animate_start && viewportY < animate_end) {
    const percent = getPercent(viewportY, animate_start, textData.distanceY);
    const y = textData.getAnimationEndY(percent);
    const x = getAnimationEndX(textData.distanceX, textData.x, percent);
    textDom.setX(x);
    textDom.setY(y);
    textDom.setAlpha(percent);
  } else if (viewportY < animate_start && viewportY > animate_start - cameras_H / 2 && !textData.animate_start_disabled) {
    if (textData.name === 'textGroup11') console.log('textData.x :>> ', textData);
    if (textDom.x !== textData.x) textDom.setX(textData.x);
    if (textDom.y !== textData.y) textDom.setY(textData.y);
    if (textDom.alpha !== 0) textDom.setAlpha(0);
  } else if (viewportY > animate_end && viewportY < animate_end + cameras_H / 2 && !textData.animate_start_disabled) {
    if (textData.name === 'textGroup11') console.log('textData.endX :>> ', textData);
    if (textDom.x !== textData.endX) textDom.setX(textData.endX);
    if (textDom.y !== textData.endY) textDom.setY(textData.endY);
    if (textDom.alpha !== 1) textDom.setAlpha(1);
  }
};
